<?php


namespace Aoe\Intent\Request;

use Aoe\Attributes\Container\Dependent;
use Aoe\Core\Kernel;
use Aoe\Intent\Params;
use Aoe\Intent\Render\Render;
use Aoe\Intent\Request\Http\Session;
use Aoe\Intent\Request\Http\Url;
use Aoe\Intent\User\User;

/**
 * # http请求
 */
class Http extends Request
{
    const string METHOD_POST = 'post';
    const string URI_SESSION_KEY = '__aoe_last_uri';

    protected ?string $method = null;
    protected(set) ?string $ip = null {
        get {
            if ($this->ip === null) $this->ip = $_SERVER['REMOTE_ADDR'];
            return $this->ip;
        }
    }
    protected(set) ?string $version = null {
        get {
            if (!$this->version) {
                $this->version = isset($_SERVER['SERVER_PROTOCOL']) && $_SERVER['SERVER_PROTOCOL'] === 'HTTP/1.0' ?
                    '1.0' : '1.1';
            }
            return $this->version;
        }
    }
    protected(set) ?array $acceptableContentTypes = null {
        get {
            if ($this->acceptableContentTypes === null) {
                $this->acceptableContentTypes = isset($_SERVER['HTTP_ACCEPT']) ?
                    parse_accept_header($_SERVER['HTTP_ACCEPT']) : [];
            }
            return $this->acceptableContentTypes;
        }
    }
    public bool $acceptJson {
        get => $this->isAjax or
            $this->isPjax or
            stristr(array_keys($this->acceptableContentTypes)[0], 'json') !== false;
    }
    public bool $isAjax {
        get => isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest';
    }
    public bool $isPjax {
        get => $this->isAjax && !empty($_SERVER['HTTP_X_PJAX']);
    }

    protected(set) ?Url $url = null {
        get {
            if ($this->url === null) $this->url = new Url();
            return $this->url;
        }
    }
    protected(set) ?Session $session = null {
        get {
            if ($this->session === null) $this->session = new Session();
            return $this->session;
        }
    }
    protected(set) ?User $user = null {
        get {
            if (!$this->user) $this->user = new User($this);
            return $this->user;
        }
    }

    public function __construct(#[Dependent] protected Kernel $kernel)
    {
        parent::__construct($kernel);
        $this->kernel->Language()->setLocale($this->getAcceptLanguage());

    }

    public function pushCurrentUri(): void
    {
        $this->session?->set(static::URI_SESSION_KEY, $this->url?->makeUrl($this->getPathinfo()));
    }
    /** @noinspection PhpUnused */
    public function popCurrentUri(): string
    {
        return $this->session?->get(static::URI_SESSION_KEY, HOME_CMD);
    }

    public function fit(array $factor): bool
    {
        return !isset($factor['on']) or (strtolower($this->getMethod()) === strtolower($factor['on']));
    }
    public function getMethod(): string
    {
        if ($this->method === null) {
            $this->method = strtoupper(
                $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] ?? ($_SERVER['REQUEST_METHOD'] ?? 'GET'),
            );
        }

        return $this->method;
    }
    public function getPathinfo(): string
    {
        return $this->url?->getPathinfo();
    }
    public function getDefaultRender(): string
    {
        return $this->acceptJson ? Render::JSON : Render::HTML;
    }

    /**
     * 本地化语言
     * Returns the languages accept by the end user.
     * This is determined by the `Accept-Language` HTTP header.
     *
     * @return string
     */
    public function getAcceptLanguage(): string
    {
        if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
            $languages = array_keys(parse_accept_header($_SERVER['HTTP_ACCEPT_LANGUAGE']));
            return static::isAcceptableLanguage($languages[0], 'zh-cn');
        }
        return 'zh-cn';
    }
    protected static function isAcceptableLanguage($language, $default)
    {
        return (preg_match('/[a-z-]/i', $language)) ? $language : $default;
    }

    /**
     * ## 编译并构建完整的url
     *
     * @param string $haystack module/controller/action/key1/value1?p1/p2@file
     *
     * @return string www.host.name:port/${file}/module/controller/action/key1/value1/p1/${p1}/p2/${p2}
     */
    public function compileUrl(string $haystack): string
    {
        if (str_starts_with($haystack, '::')) return substr($haystack, 2);

        [$uri,  $file ] = explode('@', $haystack . '@');
        [$path, $query] = explode('?', $uri . '?');

        $url = $this->url?->makeUrl($path, $file);

        if (empty($query)) return $url;

        $keys = explode('/', $query);

        return rtrim($url, '/') . '/' . ltrim($this->params->encodeQueryString($keys), '/');
    }
    /**
     * ## 构建完整url
     *
     * @noinspection PhpUnused
     */
    public function buildUrl(?string $action = null, ?string $controller = null, ?Params $params = null): string
    {
        return $this->url->makeUrl($this->buildPathinfo($action, $controller, $params));
    }
    public function buildPathinfo(?string $action = null, ?string $controller = null, ?Params $params = null): string
    {
        return $this->section->forkPathinfo($action, $controller, $params);
    }

    protected function fill_param(): array
    {
        if (
            $this->getMethod() === 'POST'
            && isset($_SERVER["CONTENT_TYPE"])
            && str_contains(strtolower($_SERVER["CONTENT_TYPE"]), 'application/json')
        ) {
            return json_decode(file_get_contents('php://input'), true);
        }

        return $_REQUEST ?? [];
    }
}